package com.google.code.instrumentation.logging;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

public abstract class AbstractLoggingAgent implements ClassFileTransformer {

	@Override
	public final byte[] transform(final ClassLoader loader,
			final String className, final Class<?> classBeingRedefined,
			final ProtectionDomain protectionDomain,
			final byte[] classfileBuffer) throws IllegalClassFormatException {
		final ClassPool cp = new ClassPool();
		cp.appendSystemPath();
		try {
			final CtClass ctClass = cp.makeClass(new ByteArrayInputStream(
					classfileBuffer));
			instrumentClass(ctClass);
			return ctClass.toBytecode();
		} catch (final IOException e) {
			throw new IllegalClassFormatException(
					"IOException trying to create CtClass: "
							+ e.getLocalizedMessage());
		} catch (final RuntimeException e) {
			// Frozen class with same name...
			// Therefore no change made
			return null;
		} catch (final CannotCompileException e) {
			// should not happen
			throw new RuntimeException("Failed to instrument class", e);
		}
	}

	private final void instrumentClass(final CtClass ctClass)
			throws CannotCompileException {
		final CtMethod[] methods = ctClass.getDeclaredMethods();
		for (final CtMethod ctMethod : methods) {
			final LoggingMethodInstrumentor mi = createInstrumentor(ctMethod);
			mi.instrumentMethod();
		}

	}

	protected abstract LoggingMethodInstrumentor createInstrumentor(
			CtMethod method);

}
